package cn.iocoder.yudao.module.dating.service.pay;

import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.module.dating.controller.app.pay.vo.PayOrderCreateReqVO;
import cn.iocoder.yudao.module.dating.dal.dataobject.order.PayWalletOrderDO;
import cn.iocoder.yudao.module.dating.dal.mysql.smallNote.PayWalletOrderMapper;
import cn.iocoder.yudao.module.dating.enums.NotePayEnum;
import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi;
import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO;
import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoOrderDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO;
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum;
import cn.iocoder.yudao.module.pay.service.wallet.PayWalletService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Objects;

import static cn.hutool.core.util.ObjectUtil.notEqual;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime;
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;

/**
 * <p>  </p>
 */
@Service
@Slf4j
public class NotePayWalletOrderServiceImpl implements NotePayWalletOrderService{
    private static final Long APPID = 1L;
    @Resource
    private PayOrderApi payOrderApi;
    @Resource
    private PayRefundApi payRefundApi;
    @Resource
    private PayWalletOrderMapper payWalletOrderMapper;
    @Resource
    private PayWalletService payWalletService;
    /**
     * 创建示例订单
     *
     * @param userId      用户编号
     * @param createReqVO 创建信息
     * @return 编号
     */
    @Override
    public Long createOrder(Long userId, @Valid PayOrderCreateReqVO createReqVO) {
        NotePayEnum notePayEnum = NotePayEnum.getById(createReqVO.getSpuId());
        Assert.notNull(notePayEnum);
        PayWalletOrderDO payWalletOrderDO = new PayWalletOrderDO().setUserId(getLoginUserId())
                .setNotePayId(notePayEnum.getId())
                .setDes(notePayEnum.getDes())
                .setCurrency(notePayEnum.getCurrency().intValue())
                .setMoney(notePayEnum.getMoney().intValue())
                .setPrice(notePayEnum.getMoney().intValue()).setPayStatus(false).setRefundPrice(0);
        payWalletOrderMapper.insert(payWalletOrderDO);
        // 创建订单
        PayOrderCreateReqDTO reqDTO = new PayOrderCreateReqDTO()
                .setAppId(APPID)
                .setUserIp(ServletUtils.getClientIP())
                .setMerchantOrderId(payWalletOrderDO.getId().toString()) // 业务的订单编号
                .setSubject(payWalletOrderDO.getDes()).setBody("").setPrice(payWalletOrderDO.getPrice()) // 价格信息
                .setExpireTime(addTime(Duration.ofHours(2L))); // 支付的过期时间
        Long order = payOrderApi.createOrder(reqDTO);
        payWalletOrderMapper.updateById(new PayWalletOrderDO().setId(payWalletOrderDO.getId()).setPayOrderId(order));
        return order;
    }

    /**
     * 获得示例订单
     *
     * @param id 编号
     * @return 示例订单
     */
    @Override
    public PayDemoOrderDO getDemoOrder(Long id) {
        return null;
    }

    /**
     * 获得示例订单分页
     *
     * @param pageReqVO 分页查询
     * @return 示例订单分页
     */
    @Override
    public PageResult<PayDemoOrderDO> getDemoOrderPage(PageParam pageReqVO) {
        return null;
    }

    /**
     * 更新示例订单为已支付
     *
     * @param id         编号
     * @param payOrderId 支付订单号
     */
    @Override
    public void updateDemoOrderPaid(Long id, Long payOrderId) {
        // 校验并获得支付订单（可支付）
        PayOrderRespDTO payOrder = validateDemoOrderCanPaid(id, payOrderId);

        // 更新 PayDemoOrderDO 状态为已支付
        int updateCount = payWalletOrderMapper.updateByIdAndPayed(id, false,
                new PayWalletOrderDO().setPayStatus(true).setPayTime(LocalDateTime.now())
                        .setPayChannelCode(payOrder.getChannelCode()));
        if (updateCount == 0) {
            throw exception(DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
        }
        PayWalletOrderDO order = payWalletOrderMapper.selectById(id);
        PayWalletDO payWalletDO = payWalletService.getOrCreateWallet(order.getUserId(), UserTypeEnum.MEMBER.getValue());
        payWalletService.addWalletBalance(payWalletDO.getId(), order.getId().toString(), PayWalletBizTypeEnum.RECHARGE, order.getCurrency());
    }

    /**
     * 发起示例订单的退款
     *
     * @param id     编号
     * @param userIp 用户编号
     */
    @Override
    public void refundDemoOrder(Long id, String userIp) {

    }

    /**
     * 更新示例订单为已退款
     *
     * @param id          编号
     * @param payRefundId 退款订单号
     */
    @Override
    public void updateDemoOrderRefunded(Long id, Long payRefundId) {
        // 1. 校验并获得退款订单（可退款）
        PayRefundRespDTO payRefund = validateDemoOrderCanRefunded(id, payRefundId);
        // 2.2 更新退款单到 demo 订单
        payWalletOrderMapper.updateById(new PayWalletOrderDO().setId(id)
                .setRefundTime(payRefund.getSuccessTime()));
        PayWalletOrderDO order = payWalletOrderMapper.selectById(id);
        PayWalletDO payWalletDO = payWalletService.getOrCreateWallet(order.getUserId(), UserTypeEnum.MEMBER.getValue());
        payWalletService.reduceWalletBalance(payWalletDO.getId(), order.getId(), PayWalletBizTypeEnum.PAYMENT_REFUND, order.getCurrency());
    }

    private PayRefundRespDTO validateDemoOrderCanRefunded(Long id, Long payRefundId) {
        // 1.1 校验示例订单
        PayWalletOrderDO order = payWalletOrderMapper.selectById(id);
        if (order == null) {
            throw exception(DEMO_ORDER_NOT_FOUND);
        }
        // 1.2 校验退款订单匹配
        if (Objects.equals(order.getPayRefundId(), payRefundId)) {
            log.error("[validateDemoOrderCanRefunded][order({}) 退款单不匹配({})，请进行处理！order 数据是：{}]",
                    id, payRefundId, toJsonString(order));
            throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR);
        }

        // 2.1 校验退款订单
        PayRefundRespDTO payRefund = payRefundApi.getRefund(payRefundId);
        if (payRefund == null) {
            throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_NOT_FOUND);
        }
        // 2.2
        if (!PayRefundStatusEnum.isSuccess(payRefund.getStatus())) {
            throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_NOT_SUCCESS);
        }
        // 2.3 校验退款金额一致
        if (notEqual(payRefund.getRefundPrice(), order.getPrice())) {
            log.error("[validateDemoOrderCanRefunded][order({}) payRefund({}) 退款金额不匹配，请进行处理！order 数据是：{}，payRefund 数据是：{}]",
                    id, payRefundId, toJsonString(order), toJsonString(payRefund));
            throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH);
        }
        // 2.4 校验退款订单匹配（二次）
        if (notEqual(payRefund.getMerchantOrderId(), id.toString())) {
            log.error("[validateDemoOrderCanRefunded][order({}) 退款单不匹配({})，请进行处理！payRefund 数据是：{}]",
                    id, payRefundId, toJsonString(payRefund));
            throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR);
        }
        return payRefund;
    }

    /**
     * 校验交易订单满足被支付的条件
     *
     * 1. 交易订单未支付
     * 2. 支付单已支付
     *
     * @param id 交易订单编号
     * @param payOrderId 支付订单编号
     * @return 交易订单
     */
    private PayOrderRespDTO validateDemoOrderCanPaid(Long id, Long payOrderId) {
        // 1.1 校验订单是否存在
        PayWalletOrderDO order = payWalletOrderMapper.selectById(id);
        if (order == null) {
            throw exception(DEMO_ORDER_NOT_FOUND);
        }
        // 1.2 校验订单未支付
        if (order.getPayStatus()) {
            log.error("[validateDemoOrderCanPaid][order({}) 不处于待支付状态，请进行处理！order 数据是：{}]",
                    id, toJsonString(order));
            throw exception(DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
        }
        // 1.3 校验支付订单匹配
        if (notEqual(order.getPayOrderId(), payOrderId)) { // 支付单号
            log.error("[validateDemoOrderCanPaid][order({}) 支付单不匹配({})，请进行处理！order 数据是：{}]",
                    id, payOrderId, toJsonString(order));
            throw exception(DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
        }

        // 2.1 校验支付单是否存在
        PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId);
        if (payOrder == null) {
            log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 不存在，请进行处理！]", id, payOrderId);
            throw exception(PAY_ORDER_NOT_FOUND);
        }
        // 2.2 校验支付单已支付
        if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) {
            log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 未支付，请进行处理！payOrder 数据是：{}]",
                    id, payOrderId, toJsonString(payOrder));
            throw exception(DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS);
        }
        // 2.3 校验支付金额一致
        if (notEqual(payOrder.getPrice(), order.getPrice())) {
            log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 支付金额不匹配，请进行处理！order 数据是：{}，payOrder 数据是：{}]",
                    id, payOrderId, toJsonString(order), toJsonString(payOrder));
            throw exception(DEMO_ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH);
        }
        // 2.4 校验支付订单匹配（二次）
        if (notEqual(payOrder.getMerchantOrderId(), id.toString())) {
            log.error("[validateDemoOrderCanPaid][order({}) 支付单不匹配({})，请进行处理！payOrder 数据是：{}]",
                    id, payOrderId, toJsonString(payOrder));
            throw exception(DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
        }
        return payOrder;
    }

}
